import type { Iso, Name, CName } from './map'
import LanguageDetect from '../languagedetect'
import chekers from './chekers'
import { isoNameMap, isoCnameMap } from './map'

/** 支持的拉丁语种code */
export const supportedLatinLangs = ['ru', 'en', 'id', 'es', 'it', 'fr', 'de']

/** 支持的特殊符号语种code */
export const supportedSpecLangs = ['zh', 'ja', 'th', 'ko']

/**
 * 检测特殊符号语言
 * @param content
 * @returns {{ exsitEnglish: boolean; list: Array<{ precision: number; iso: string }>; }}
 */
export const getSpecLangCheck = (content: string) => {
  const strings = content ? content.replace(/[~!@#$%^&*()_|+\-=?;:",.<>{}[]\\\/]/g, ' ') : '';
  const langMap: Record<string, boolean> = {}
  const langs = chekers.reduce<Array<{ precision: number; iso: string; }>>((list, checker) => {
    const { count, percent, iso } = checker.check(strings)
    // 若为英语，则英文字母数大于1%时判定为英语，若不是，只要有1个字符则认为是该语言
    if ((iso !== 'en' && count > 0) || (iso === 'en' && percent > 1)) {
      langMap[iso] = true
      return [
        ...list,
        {
          precision: percent,
          iso,
        },
      ]
    }
    return list
  }, [])

  return {
    exsitEnglish: langMap['en'],
    list: langs.filter(lang => langMap['ja'] && langMap['zh'] ? lang.iso !== 'zh' : true),
  }
}

/**
 * 检测拉丁体系语言
 * @param content
 * @returns  {Array<{ precision: number; iso: string }>}
 */
export const getLatinLangsCheck = (content: string) => {
  // 生成10个识别结果，过滤掉分值小于0.1的结果，并取前两个
  const langs = new LanguageDetect({
    languageType: 'iso2',
    supportLangs: supportedLatinLangs.map(iso => isoNameMap[iso]),
  }).detect(content, 10).filter(([, score]) => score > 0.1).slice(0, 2)
  console.log('get 2 latin langs:', langs)
  const total = langs.reduce((sum, [, score]) => sum + score, 0)

  // 过滤出三者中分值比大于45的语言
  return langs.filter(([, score]) => Math.floor(score * 100 / total) > 45).map(([iso, score]) => ({
    precision: Number((score * 100 / total).toFixed(2)),
    iso,
  }))
}

/**
 * 获取检测出的语言列表
 * @param content 要检测的字符串
 * @returns {{ Array<{ precision: number; iso: string; }> }} 返回语言中可能包含的语言以及可信度
 */
export const getCheckLanguages = (content: string) => {
  const latinLangs = getLatinLangsCheck(content)
  console.log('final latin langs:', latinLangs)

  const { exsitEnglish, list: specLangs } = getSpecLangCheck(content)
  console.log('final spec langs:', specLangs)

  return [
    ...latinLangs,
    ...specLangs.filter(lang =>
      latinLangs.length && exsitEnglish
        ? lang.iso !== 'en'
        : true
    ),
  ]
}

interface CheckResult {
  /** 存在致命阻断 */
  fatal: boolean
  /** 支持的语种中文名 */
  supportLangCnames: CName[]
  /** 不支持的语种中文名 */
  unSupportLangCnames: CName[]
}

/**
 * 语言检测
 * @param content 要检测的字符串
 * @param curLangs 当前允许的语言，若待检测列表为空，则不予检测
 * @returns 返回检测状态、语种支持与不支持情况
 */
export const languageCheck = (content: string, curLangs: Iso[]) => {
  const checkResult: CheckResult = {
    /** 存在致命阻断 */
    fatal: false,
    /** 支持的语种中文名 */
    supportLangCnames: curLangs.map(iso => isoCnameMap[iso]),
    /** 不支持的语种中文名 */
    unSupportLangCnames: new Array<CName>(),
  }

  const langs = getCheckLanguages(content)
  console.log('check languages:', langs)

  // 仅配置了支持语种并检测存在语种
  if (curLangs.length > 0 && langs.length > 0) {
    console.log('check start')
    langs.map<Name>(({ iso }) => isoNameMap[iso])
    /** 不支持的语种code */
    const unSupportLangIsos = langs.reduce<Array<Iso>>((list, { iso }) => {
      if (curLangs.includes(iso)) return list
      return [
        ...list,
        iso,
      ]
    }, [])
    checkResult.unSupportLangCnames = unSupportLangIsos.map<CName>(iso => isoCnameMap[iso])

    /** 存在至少一种不支持的特殊符号语种 */
    const hasNotSupportSpec = !!unSupportLangIsos.find(iso => supportedSpecLangs.includes(iso))

    /** 仅支持特殊符号语种 */
    const onlySupportSpec = curLangs.every(iso => supportedSpecLangs.includes(iso))

    /** 仅支持拉丁语种 */
    const onlySupportLatin = curLangs.every(iso => supportedLatinLangs.includes(iso))

    /** 仅存在特殊符号语种 */
    const onlyExsitSpec = langs.every(({ iso }) => supportedSpecLangs.includes(iso))

    /** 仅存在拉丁语种 */
    const onlyExsitLatin = langs.every(({ iso }) => supportedLatinLangs.includes(iso))

    if ((onlySupportSpec && !onlyExsitSpec) || (onlySupportLatin && !onlyExsitLatin)) {
      // 如果是不同体系语种，识别阻断致命
      checkResult.fatal = true
    } else if (onlySupportSpec && onlyExsitSpec && unSupportLangIsos.length) {
      // 如果是纯特殊字符语种，且包含不支持的语言，则识别阻断致命
      checkResult.fatal = true
    } else if (!onlySupportLatin && onlyExsitSpec && hasNotSupportSpec) {
      // 如果是特殊字符与拉丁语混合语种，且存在不支持特殊字符语言，则识别阻断致命
      checkResult.fatal = true
    }
  }

  console.log('check result:', checkResult)
  return checkResult
}

export * from './map'
